using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using WebAuth.DAO;
using WebAuth.Models;

namespace WebAuth.Bussiness
{
    public class CacheManager
    {
        private UapDbContext _dbContext = DbManager.GetDbContext();
        Dictionary<Type, IDictionary> _modelSets = new Dictionary<Type, IDictionary>();
        private static CacheManager _me;
        private uint _authCacheVersion = 0;
        private readonly object _authVerLocker = new object();

        public uint GetCachVersion()
        {
            return _authCacheVersion;
        }

        public void ChangeAutchCacheVer()
        {
            lock (_authVerLocker)
            {
                _authCacheVersion++;
                if (_authCacheVersion == uint.MaxValue)
                {
                    _authCacheVersion = uint.MinValue;
                    LoadCache();
                }
            }
        }

        public static CacheManager GetCacheManager()
        {
            if (_me == null)
            {
                _me = new CacheManager();
            }

            return _me;
        }


        public void LoadCache()
        {
            LoadModelSet(_dbContext.AuthItems);
            BindChildren<AuthGroup, AuthItem>(LoadModelSet(_dbContext.AuthGroups));
            LoadModelSet(_dbContext.Roles);
            LoadModelSet(_dbContext.Departments);
            BindChildren<AuthBinder, AuthGroup>(LoadModelSet(_dbContext.AuthBinders));
            BindChildren<User, AuthBinder>(LoadModelSet(_dbContext.Users));
        }

        public void BindChildren<T, TC>(Dictionary<string, T> set)
            where T : AuthModel
            where TC : IDbEntity
        {
            foreach (var value in set.Values)
            {
                value.SetAuthChildren<TC>();
            }
        }

        public Dictionary<string, T> LoadModelSet<T>(DbSet<T> dbSet) where T : class, IDbEntity
        {
            Dictionary<string, T> modelSet = new Dictionary<string, T>();
            var list = dbSet.ToList();
            foreach (var item in list)
            {
                modelSet.TryAdd(item.Id, item);
            }

            _modelSets[typeof(T)] = modelSet;
            return modelSet;
        }

        public void GetModelSet<T>(out Dictionary<string, T> modelSet) where T : IDbEntity
        {
            modelSet = default;
            if (_modelSets.ContainsKey(typeof(T)))
            {
                modelSet = _modelSets[typeof(T)] as Dictionary<string, T>;
            }
        }

        public void GetModelById<T>(string id, out T cache) where T : class
        {
            if (string.IsNullOrEmpty(id))
                throw new ArgumentException("Id is needed!");
            cache = default(T);
            if (_modelSets.ContainsKey(typeof(T)))
            {
                cache = _modelSets[typeof(T)][id] as T;
            }
        }
    }
}